/*
 * $Id: pkt.h,v 1.75.6.3 Broadcom SDK $
 * 
 * $Copyright: Copyright 2011 Broadcom Corporation.
 * This program is the proprietary software of Broadcom Corporation
 * and/or its licensors, and may only be used, duplicated, modified
 * or distributed pursuant to the terms and conditions of a separate,
 * written license agreement executed between you and Broadcom
 * (an "Authorized License").  Except as set forth in an Authorized
 * License, Broadcom grants no license (express or implied), right
 * to use, or waiver of any kind with respect to the Software, and
 * Broadcom expressly reserves all rights in and to the Software
 * and all intellectual property rights therein.  IF YOU HAVE
 * NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS SOFTWARE
 * IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
 * ALL USE OF THE SOFTWARE.  
 *  
 * Except as expressly set forth in the Authorized License,
 *  
 * 1.     This program, including its structure, sequence and organization,
 * constitutes the valuable trade secrets of Broadcom, and you shall use
 * all reasonable efforts to protect the confidentiality thereof,
 * and to use this information only in connection with your use of
 * Broadcom integrated circuit products.
 *  
 * 2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS
 * PROVIDED "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
 * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
 * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE.  BROADCOM SPECIFICALLY
 * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
 * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
 * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
 * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING
 * OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
 * 
 * 3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL
 * BROADCOM OR ITS LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL,
 * INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY DAMAGES WHATSOEVER
 * ARISING OUT OF OR IN ANY WAY RELATING TO YOUR USE OF OR INABILITY
 * TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF
 * THE AMOUNT ACTUALLY PAID FOR THE SOFTWARE ITSELF OR USD 1.00,
 * WHICHEVER IS GREATER. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING
 * ANY FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.$
 * 
 * DO NOT EDIT THIS FILE!
 * This file is auto-generated.
 * Edits to this file will be lost when it is regenerated.
 */

#ifndef __BCM_PKT_H__
#define __BCM_PKT_H__

#include <shared/rx.h>
#include <bcm/types.h>

/* Default TX and RX DMA channels for the BCM layer. */
#define BCM_TX_CHAN_DFLT        0          
#define BCM_RX_CHAN_DFLT        1          

/* Minimum packet allocation:  MAC addresses, VLAN tag, CRC. */
#define BCM_PKT_ALLOC_MIN       (12 + 4 + 4) 

/* 
 * IEEE header:  MAC addresses + VLAN tag; does not include type/len
 * field.
 */
#define BCM_IEEE_HDR_BYTES      (12 + 4)   

/* 
 * The packet structure. The packet layout is as follows:
 * 
 *   DMAC + SMAC     12 bytes
 *   VLAN tag         4 bytes (may be filled in by SW on BCM5670/75)
 *   payload          N bytes
 *   CRC              4 bytes
 *   pad              M bytes
 *   SL tag           4 bytes (may be unused)
 *   HiGig Header    12 bytes (may be unused)
 * 
 * The rule is: alloc_len = 12 + 4 + N + 4 + M + 4 + 12 (all of above).
 * payload_len (below) is N.
 * 
 * Note that the payload may grow until M == 0; the CRC moves. The SL and
 * HiGig headers will not move.
 * 
 * The "IEEE packet" is everything from the DMAC through the CRC
 * (inclusive), not including SL tag or HiGig header.
 * 
 * Scatter/gather is used to put the data into the right positions on
 * transmit and receive. The SL/HiGig headers are parsed on RX into data
 * members in the packet structure. On TX, bcm_tx will send the packet
 * according to the unit type. It will not check or affect any fields
 * except maybe the CRC. Other routines will be provided to ensure the
 * HiGig and SL tags are properly set up from the data in the packet
 * structure.
 */
typedef struct bcm_pkt_s bcm_pkt_t;

/* bcm_pkt_cb_f */
typedef void (*bcm_pkt_cb_f)(
    int unit, 
    bcm_pkt_t *pkt, 
    void *cookie);

/* BCM packet gather block type. */
typedef struct bcm_pkt_blk_s {
    uint8 *data; 
    int len; 
} bcm_pkt_blk_t;

/* Set of 'reasons' (see bcmRxReason*) why a packet came to the CPU. */
typedef _shr_rx_reasons_t bcm_rx_reasons_t;

/* Stacking header packet forwarding options. */
typedef enum bcm_pkt_stk_forward_e {
    BCM_PKT_STK_FORWARD_CPU,            /* Stacking header packet forwarding
                                           option: to Host CPU. */
    BCM_PKT_STK_FORWARD_L2_UNICAST,     /* Stacking header packet forwarding
                                           option: Unicast L2. */
    BCM_PKT_STK_FORWARD_L3_UNICAST,     /* Stacking header packet forwarding
                                           option: Unicast L3. */
    BCM_PKT_STK_FORWARD_L2_MULTICAST,   /* Stacking header packet forwarding
                                           option: Multicast L2. */
    BCM_PKT_STK_FORWARD_L2_MULTICAST_UNKNOWN, /* Stacking header packet forwarding
                                           option: Unknown Multicast L2. */
    BCM_PKT_STK_FORWARD_L3_MULTICAST,   /* Stacking header packet forwarding
                                           option: Multicast L3. */
    BCM_PKT_STK_FORWARD_L3_MULTICAST_UNKNOWN, /* Stacking header packet forwarding
                                           option: Unknown Multicast L3. */
    BCM_PKT_STK_FORWARD_L2_UNICAST_UNKNOWN, /* Stacking header packet forwarding
                                           option: Unknown Unicast L2. */
    BCM_PKT_STK_FORWARD_BROADCAST,      /* Stacking header packet forwarding
                                           option: Broadcast. */
    BCM_PKT_STK_FORWARD_COUNT           /* Must be last. */
} bcm_pkt_stk_forward_t;

/* Initialize a BCM packet structure. */
struct bcm_pkt_s { 
    bcm_pkt_blk_t *pkt_data;            /* Pointer to array of data blocks. */
    uint8 blk_count;                    /* Number of blocks in data array. */
    uint8 unit;                         /* Unit number. */
    uint8 cos;                          /* The local COS queue to use. */
    uint8 prio_int;                     /* Internal priority of the packet. */
    bcm_vlan_t vlan;                    /* 802.1q VID or VSI or VPN. */
    uint8 vlan_pri;                     /* Vlan tag priority . */
    uint8 vlan_cfi;                     /* Vlan tag CFI bit. */
    bcm_vlan_t inner_vlan;              /* Inner VID or VSI or VPN. */
    uint8 inner_vlan_pri;               /* Inner vlan tag priority . */
    uint8 inner_vlan_cfi;               /* Inner vlan tag CFI bit. */
    bcm_color_t color;                  /* Packet color. */
    int8 src_port;                      /* Source port used in header/tag. */
    int8 src_trunk;                     /* Source trunk group ID used in
                                           header/tag, -1 if src_port set . */
    uint16 src_mod;                     /* Source module ID used in header/tag. */
    uint8 dest_port;                    /* Destination port used in header/tag. */
    uint16 dest_mod;                    /* Destination module ID used in
                                           header/tag. */
    uint8 opcode;                       /* BCM_HG_OPCODE_xxx. */
    bcm_gport_t dst_gport;              /* Destination virtual port */
    bcm_gport_t src_gport;              /* Source virtual port */
    bcm_multicast_t multicast_group;    /* Destination multicast group. */
    uint32 stk_flags;                   /* Stacking header flags. */
    bcm_pkt_stk_forward_t stk_forward;  /* Stacking header forwarding opcode. */
    uint32 stk_classification_tag;      /* Stacking header classification tag. */
    uint32 stk_pkt_prio;                /* Stacking header new packet priority. */
    uint32 stk_dscp;                    /* Stacking header new DSCP. */
    uint32 stk_load_balancing_number;   /* Stacking header load balancing
                                           number. */
    uint16 pkt_len;                     /* Packet length according to flags. */
    uint16 tot_len;                     /* Packet length as transmitted or
                                           received. */
    bcm_pbmp_t tx_pbmp;                 /* Target ports. */
    bcm_pbmp_t tx_upbmp;                /* Untagged target ports. */
    bcm_pbmp_t tx_l3pbmp;               /* L3 ports. */
    uint8 pfm;                          /* BCM_PORT_PFM_xxx flags. */
    uint32 rx_reason;                   /* Opcode from packet. */
    bcm_rx_reasons_t rx_reasons;        /* Set of packet "reasons". */
    uint8 rx_unit;                      /* Local rx unit. */
    uint8 rx_port;                      /* Local rx port; not in HG hdr. */
    uint8 rx_cpu_cos;                   /* CPU may get pkt on diff cos. */
    uint8 rx_untagged;                  /* The packet was untagged on ingress. */
    uint32 rx_classification_tag;       /* Classification tag. */
    uint32 rx_matched;                  /* Field processor matched rule. */
    uint32 rx_timestamp;                /* Time stamp of time sync protocol
                                           packets. */
    uint32 rx_timestamp_upper;          /* Upper 32-bit of 64-bit timestamp of
                                           OAM DM. */
    uint32 timestamp_flags;             /* Timestamp flags. */
    void *cookie;                       /* User data for callback. */
    void *cookie2;                      /* Additional user data for callback. */
    bcm_pkt_cb_f call_back;             /* Callback function. */
    uint32 flags;                       /* BCM_PKT_F_xxx flags. */
    void *next;                         /* When linked into lists. */
    int8 dma_channel;                   /* DMA channel used; may be -1. */
    bcm_pkt_blk_t _pkt_data;            /* For single block packets (internal). */
    bcm_pkt_t *_last_pkt;               /* To link to end of linked lists
                                           (internal). */
    void *_dv;                          /* DV controlling this packet
                                           (internal). */
    int8 _idx;                          /* Packet's index in the DV for RX
                                           (internal). */
    bcm_pkt_t *_next;                   /* For BCM layer linked lists
                                           (internal). */
    void *alloc_ptr;                    /* Pointer for deallocation (internal). */
    void *trans_ptr;                    /* Transport pointer associated with
                                           packet (internal). */
    uint8 _higig[16];                   /* HiGig header value (network byte
                                           order). */
    uint8 _pb_hdr[12];                  /* Pipe Bypass Header (network byte
                                           order). */
    uint8 _sltag[4];                    /* SL tag value (network byte order). */
    uint8 _vtag[4];                     /* VLAN tag if not in packet (network
                                           byte order). */
    uint8 _sbx_rh[16];                  /* SBX Route Header & Shim. */
    uint8 _sbx_hdr_len;                 /* Length of SBX header(s). */
    int flow_id;                        /* Internal flow id. */
    uint32 filter_enable;               /* filters to be enabled. */
    bcm_pbmp_t _dv_tx_pbmp;             /* Actual pbmp assigned to tx
                                           descriptor(internal). */
    bcm_pbmp_t _dv_tx_upbmp;            /* Actual upbmp assigned to tx
                                           descriptor(internal). */
};

/* HiGig opcodes. */
#define BCM_HG_OPCODE_CPU       0x00       /* CPU Frame. */
#define BCM_HG_OPCODE_UC        0x01       /* Unicast Frame. */
#define BCM_HG_OPCODE_BC        0x02       /* Broadcast or DLF frame. */
#define BCM_HG_OPCODE_MC        0x03       /* Multicast Frame. */
#define BCM_HG_OPCODE_IPMC      0x04       /* IP Multicast Frame. */

/* Generic packet opcodes. */
#define BCM_PKT_OPCODE_CPU      0x00       /* CPU Frame. */
#define BCM_PKT_OPCODE_UC       0x01       /* Unicast Frame. */
#define BCM_PKT_OPCODE_BC       0x02       /* Broadcast or DLF frame. */
#define BCM_PKT_OPCODE_MC       0x03       /* Multicast Frame. */
#define BCM_PKT_OPCODE_IPMC     0x04       /* IP Multicast Frame. */

/* Packet flags. */
#define BCM_PKT_F_HGHDR             0x1        /* HiGig header is active
                                                  (internal). */
#define BCM_PKT_F_SLTAG             0x2        /* SL tag is active. */
#define BCM_PKT_F_NO_VTAG           0x4        /* Packet does not contain VLAN
                                                  tag. */
#define BCM_PKT_F_TX_UNTAG          0x8        /* TX packet untagged (internal). */
#define BCM_TX_CRC_FLD              0xf0       /* CRC information */
#define BCM_TX_CRC_ALLOC            0x10       /* Allocate buffer for CRC. */
#define BCM_TX_CRC_REGEN            0x20       /* Regenerate CRC. */
#define BCM_TX_CRC_APPEND           (BCM_TX_CRC_ALLOC + BCM_TX_CRC_REGEN) 
#define BCM_TX_CRC_FORCE_ERROR      0x40       /* Force CRC error. */
#define BCM_TX_NO_PAD               0x100      /* Do not pad runt packets. */
#define BCM_TX_FAST_PATH            0x200      /* Fast path TX. */
#define BCM_TX_PURGE                0x400      /* XGS3 Set PURGE bit in DCB
                                                  (internal). */
#define BCM_TX_LINKDOWN_TRANSMIT    0x800      /* Transmit on link down ports */
#define BCM_TX_RELIABLE             0x1000     /* Relay (tunnel) packet
                                                  reliably. */
#define BCM_TX_BEST_EFFORT          0x2000     /* Use best effort to relay
                                                  packet. */
#define BCM_TX_LOOPBACK             0x4000     /* Loopback is indicated. */
#define BCM_TX_SBX_READY            0x8000     /* SBX Route header in _sbx_rh. */
#define BCM_TX_PKT_PROP_ANY         0xf0000    /* All packet property fields. */
#define BCM_TX_SRC_MOD              0x10000    /* Use the src_mod field from
                                                  packet. */
#define BCM_TX_SRC_PORT             0x20000    /* Use the src_port field from
                                                  packet. */
#define BCM_TX_PRIO_INT             0x40000    /* Use the prio_int field from
                                                  packet. */
#define BCM_TX_PFM                  0x80000    /* Use PFM field from packet. */
#define BCM_TX_ETHER                0x100000   /* Fully mapped packet TX. */
#define BCM_TX_HG_READY             0x200000   /* HiGig header in _higig. */
#define BCM_TX_TIME_STAMP_REPORT    0x400000   /* Request transmit time stamp. */
#define BCM_RX_LEARN_DISABLED       0x800000   /* Packet's SA is not learned. */
#define BCM_RX_CRC_STRIP            0x1000000  /* Do not include the CRC in the
                                                  length of the packet. */
#define BCM_RX_TUNNELLED            0x2000000  /* Packet was tunnelled. */
#define BCM_RX_MIRRORED             0x4000000  /* Packet was mirrored. */
#define BCM_RX_TRUNCATED            0x8000000  /* Packet was truncated. */
#define BCM_PKT_F_TIMESYNC          0x10000000 /* Packet is for Time Sync
                                                  protocol. */
#define BCM_PKT_F_TRUNK             0x20000000 /* Trunk port. */
#define BCM_PKT_F_TEST              0x40000000 /* Set the Test bit. */
#define BCM_PKT_F_ROUTED            0x80000000 /* L3 switched packet. */

/* Flags for rx_untagged field in bcm_pkt_t structure. */
#define BCM_PKT_OUTER_UNTAGGED  0x1        /* Packet received without outer vlan
                                              tag. */
#define BCM_PKT_INNER_UNTAGGED  0x2        /* Packet received without inner vlan
                                              tag. */

/* TimeSync Packet Flags. */
#define BCM_TX_TIMESYNC_ONE_STEP            0x1        /* One step timestamp. */
#define BCM_TX_TIMESYNC_ONE_STEP_INGRESS_SIGN 0x2        /* Ingress timestamp sign
                                                          bit. */
#define BCM_TX_TIMESYNC_ONE_STEP_HDR_START_OFFSET 0x4        /* One step timestamp
                                                          header offset. */
#define BCM_TX_TIMESYNC_ONE_STEP_REGEN_UDP_CHKSUM 0x8        /* One step timestamp
                                                          header offset. */

/* Stacking Packet flags. */
#define BCM_PKT_STK_F_MIRROR                0x1        /* Mirror packet. */
#define BCM_PKT_STK_F_DO_NOT_MODIFY         0x2        /* Do not alter packet on
                                                          egress device. */
#define BCM_PKT_STK_F_TRUNK_FAILOVER        0x4        /* Packet is redirected
                                                          due to trunk failover. */
#define BCM_PKT_STK_F_SRC_PORT              0x8        /* Source GPORT provided. */
#define BCM_PKT_STK_F_DST_PORT              0x10       /* Destination GPORT
                                                          provided. */
#define BCM_PKT_STK_F_DEFERRED_DROP         0x20       /* Drop in egress device. */
#define BCM_PKT_STK_F_DEFERRED_CHANGE_PKT_PRIO 0x40       /* Update packet priority
                                                          to stk_pkt_prio in
                                                          egress device. */
#define BCM_PKT_STK_F_DEFERRED_CHANGE_DSCP  0x80       /* Update DSCP to
                                                          stk_dscp in egress
                                                          device. */
#define BCM_PKT_STK_F_CLASSIFICATION_TAG    0x100      /* stk_classification_tag
                                                          field is valid. */
#define BCM_PKT_STK_F_VLAN_TRANSLATE_NONE   0x200      /* No VLAN translation
                                                          performed. */
#define BCM_PKT_STK_F_VLAN_TRANSLATE_UNCHANGED 0x400      /* VLAN translation did
                                                          not change packet. */
#define BCM_PKT_STK_F_VLAN_TRANSLATE_CHANGED 0x800      /* VLAN translation
                                                          changed packet. */
#define BCM_PKT_STK_F_DO_NOT_LEARN          0x1000     /* Packet should not be
                                                          learned on egress
                                                          device. */
#define BCM_PKT_STK_F_PRESERVE_DSCP         0x2000     /* Egress device should
                                                          not change DSCP. */
#define BCM_PKT_STK_F_PRESERVE_PKT_PRIO     0x4000     /* Egress device should
                                                          not change packet
                                                          priority. */
#define BCM_PKT_STK_F_TX_TAG                0x8000     /* The VLAN tag should be
                                                          included in the packet
                                                          data (internal). */

/* Filter types. */
#define BCM_PKT_FILTER_LAG          0x1        /* LAG filter. */
#define BCM_PKT_FILTER_TAGGED       0x2        /* Tag filter. */
#define BCM_PKT_FILTER_PORT_MASK    0x4        /* Port mask filter. */
#define BCM_PKT_FILTER_STP          0x8        /* STP filter. */
#define BCM_PKT_FILTER_EAP          0x10       /* EAP filter. */
#define BCM_PKT_FILTER_INGRESS_VLAN 0x20       /* Ingress Vlan filter. */
#define BCM_PKT_FILTER_EGRESS_VLAN  0x40       /* Egress Vlan filter. */
#define BCM_PKT_FILTER_SA           0x80       /* Source address filter. */

/* CPU to CPU tunnel modes. */
typedef enum bcm_cpu_tunnel_mode_e {
    BCM_CPU_TUNNEL_NONE,                /* Do not tunnel. */
    BCM_CPU_TUNNEL_PACKET_RELIABLE,     /* Use reliable transport. */
    BCM_CPU_TUNNEL_PACKET_BEST_EFFORT,  /* Use best effort transport. */
    BCM_CPU_TUNNEL_PACKET               /* Use default mode. */
} bcm_cpu_tunnel_mode_t;

/* CPU to CPU tunnel flags. */
#define BCM_CPU_TUNNEL_F_UNTAGGED       0x1        /* Untagged packet. */
#define BCM_CPU_TUNNEL_F_L3             0x2        /* L3 packet. */
#define BCM_CPU_TUNNEL_F_PBMP           0x4        /* Use port bitmap, not just
                                                      port. */
#define BCM_CPU_TUNNEL_F_RELIABLE       0x8        /* Use reliable transport. */
#define BCM_CPU_TUNNEL_F_BEST_EFFORT    0x10       /* Use best effort transport. */
#define BCM_CPU_TUNNEL_F_ALL_UNTAGGED   0x20       /* Use with port bitmap. */

/* Backward compatibility. */
#define bcm_tunnel_mode_t       bcm_cpu_tunnel_mode_t 

/* Backward compatibility. */
#define BCM_TUNNEL_NONE             BCM_CPU_TUNNEL_NONE 
#define BCM_TUNNEL_PACKET_RELIABLE  BCM_CPU_TUNNEL_PACKET_RELIABLE 
#define BCM_TUNNEL_PACKET_NO_ACK    BCM_CPU_TUNNEL_PACKET_BEST_EFFORT 
#define BCM_TUNNEL_PACKET           BCM_CPU_TUNNEL_PACKET 

/* Backward compatibility. */
#define BCM_TUNNEL_F_UNTAGGED       BCM_CPU_TUNNEL_F_UNTAGGED 
#define BCM_TUNNEL_F_L3             BCM_CPU_TUNNEL_F_L3 
#define BCM_TUNNEL_F_PBMP           BCM_CPU_TUNNEL_F_PBMP 
#define BCM_TUNNEL_F_RELIABLE       BCM_CPU_TUNNEL_F_RELIABLE 
#define BCM_TUNNEL_F_BEST_EFFORT    BCM_CPU_TUNNEL_F_BEST_EFFORT 
#define BCM_TUNNEL_F_ALL_UNTAGGED   BCM_CPU_TUNNEL_F_ALL_UNTAGGED 

/* Set up a single buffer packet. */
#define BCM_PKT_ONE_BUF_SETUP(pkt, buf, _len)  \
    do { \
        (pkt)->_pkt_data.data = (buf); \
        (pkt)->_pkt_data.len = (_len); \
        (pkt)->pkt_data = &(pkt)->_pkt_data; \
        (pkt)->blk_count = 1; \
    } while (0) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_TX_LEN_SET(pkt, _len)  \
    (pkt)->_pkt_data.len = (_len) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define _BCM_HTONS_CVT_SET(pkt, val, posn)  \
    do { \
         uint16 _tmp; \
         _tmp = bcm_htons(val); \
         sal_memcpy((pkt)->_pkt_data.data + (posn), &_tmp, 2); \
    } while (0) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_DMAC_SET(pkt, mac)  \
    sal_memcpy((pkt)->_pkt_data.data, (mac), 6) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_SMAC_SET(pkt, mac)  \
    sal_memcpy((pkt)->_pkt_data.data + 6, (mac), 6) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_TPID_SET(pkt, tpid)  \
    _BCM_HTONS_CVT_SET(pkt, tpid, 12) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_UNTAGGED_LEN_SET(pkt, len)  \
    _BCM_HTONS_CVT_SET(pkt, len, 12) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_VTAG_CONTROL_SET(pkt, vtag)  \
    _BCM_HTONS_CVT_SET(pkt, vtag, 14) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_TAGGED_LEN_SET(pkt, len)  \
    _BCM_HTONS_CVT_SET(pkt, len, 16) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_SNAP_DSAP_SET(pkt, dsap)  \
    (pkt)->_pkt_data.data[18] = (dsap) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_SNAP_SSAP_SET(pkt, ssap)  \
    (pkt)->_pkt_data.data[19] = (ssap) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_SNAP_CONTROL_SET(pkt, ctl)  \
    (pkt)->_pkt_data.data[20] = (ctl) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_SNAP_ORG_SET(pkt, b1, b2, b3)  \
     do { \
        (pkt)->_pkt_data.data[21] = (b1); \
        (pkt)->_pkt_data.data[22] = (b2); \
        (pkt)->_pkt_data.data[23] = (b3); \
    } while (0) 

/* Helper macro for single buffer Ethernet packet (not HiGig). */
#define BCM_PKT_HDR_SNAP_ETYPE_SET(pkt, etype)  \
    _BCM_HTONS_CVT_SET(pkt, etype, 24) 

/* Set a single port for a packet for TX. */
#define BCM_PKT_PORT_SET(pkt, _port, _untagged, _l3)  \
    do { \
        BCM_PBMP_PORT_SET((pkt)->tx_pbmp, _port); \
        if ((_untagged) != FALSE) { \
            BCM_PBMP_PORT_SET((pkt)->tx_upbmp, _port); \
        } else { \
            BCM_PBMP_CLEAR((pkt)->tx_upbmp); \
        } \
        if ((_l3) != FALSE) { \
            BCM_PBMP_PORT_SET((pkt)->tx_l3pbmp, _port); \
        } else { \
            BCM_PBMP_CLEAR((pkt)->tx_l3pbmp); \
        } \
    } while (0) 

/* Check if HiGig header is active in the packet. */
#define BCM_PKT_HAS_HGHDR(pkt)  \
    (((pkt)->flags & BCM_PKT_F_HGHDR) != 0) 

#define BCM_PKT_HAS_SBX_RH(pkt)  \
    ((pkt)->_sbx_hdr_len > 0) 

/* Check if SL tag is active in the packet. */
#define BCM_PKT_HAS_SLTAG(pkt)  \
    (((pkt)->flags & BCM_PKT_F_SLTAG) != 0) 

/* Check if VLAN tag is not present in packet. */
#define BCM_PKT_NO_VLAN_TAG(pkt)  \
    (((pkt)->flags & BCM_PKT_F_NO_VTAG) != 0) 

/* Do not include CRC in length on RX. */
#define BCM_PKT_RX_CRC_STRIP(pkt)  \
    ((pkt)->flags & BCM_RX_CRC_STRIP) 

/* Strip VLAN tag on RX; do not include in length. */
#define BCM_PKT_RX_VLAN_TAG_STRIP(pkt)  \
    BCM_PKT_NO_VLAN_TAG(pkt) 

#define BCM_TX_PKT_PROP_ANY_TST(pkt)  \
    (((pkt)->flags & BCM_TX_PKT_PROP_ANY) != 0) 

#define BCM_PKT_TX_ETHER(pkt)   \
    (((pkt)->flags & BCM_TX_ETHER) != 0) 

#define BCM_PKT_TX_HG_READY(pkt)  \
    (((pkt)->flags & BCM_TX_HG_READY) != 0) 

/* 
 * Check if fabric mapped, which means that the packet is sent
 * from the CPU through the HiGig ingress pipeline.
 */
#define BCM_PKT_TX_FABRIC_MAPPED(pkt)  \
            ((((pkt)->flags & BCM_TX_ETHER ) !=0 ) && \
             (((pkt)->flags & (BCM_TX_PKT_PROP_ANY | BCM_TX_HG_READY) ) !=0 )) 

/* Pointer to beginning of IEEE packet. */
#define BCM_PKT_IEEE(pkt)       \
    ((uint8*)((pkt)->pkt_data[0].data)) 

/* Length of IEEE packet including MAC addresses and CRC. */
#define BCM_PKT_IEEE_LEN(pkt)   \
    ((pkt)->pkt_len) 

/* Pointer to destination MAC address. */
#define BCM_PKT_DMAC(pkt)       \
    BCM_PKT_IEEE(pkt) 

/* Pointer to VLAN tag (all 4 bytes). */
#define BCM_PKT_VLAN_PTR(pkt)   \
   (((pkt)->flags & BCM_PKT_F_NO_VTAG) ? (pkt)->_vtag : \
    ((BCM_PKT_DMAC(pkt) + 2*sizeof(bcm_mac_t)))) 

/* The protocol (eg 0x8100) bytes. */
#define BCM_PKT_TAG_PROTOCOL(pkt)  \
    ((uint16) ((BCM_PKT_VLAN_PTR(pkt)[0] << 8) | (BCM_PKT_VLAN_PTR(pkt)[1]))) 

/* The VLAN control tag. */
#define BCM_PKT_VLAN_CONTROL(pkt)  \
    ((uint16) ((BCM_PKT_VLAN_PTR(pkt)[2] << 8) | (BCM_PKT_VLAN_PTR(pkt)[3]))) 

/* The ID from the VLAN control tag. */
#define BCM_PKT_VLAN_ID(pkt)    \
    BCM_VLAN_CTRL_ID(BCM_PKT_VLAN_CONTROL(pkt)) 

/* The priority from the VLAN control tag. */
#define BCM_PKT_VLAN_PRI(pkt)   \
    BCM_VLAN_CTRL_PRIO(BCM_PKT_VLAN_CONTROL(pkt)) 

/* The CFI from the VLAN control tag. */
#define BCM_PKT_VLAN_CFI(pkt)   \
     BCM_VLAN_CTRL_CFI(BCM_PKT_VLAN_CONTROL(pkt)) 

/* Pointer to packet's HiGig header. */
#define BCM_PKT_HG_HDR(pkt)     \
    ((pkt)->_higig) 

/* Pointer to packet's SL tag. */
#define BCM_PKT_SL_TAG(pkt)     \
    ((pkt)->_sltag) 

/* Pointer to packet's Pipeline Bypass header. */
#define BCM_PKT_PB_HDR(pkt)     \
    ((pkt)->_pb_hdr) 

#define BCM_PKT_NO_VTAG_REQUIRE(pkt)  \
    ((pkt)->flags |= BCM_PKT_F_NO_VTAG) 

#define BCM_PKT_HGHDR_CLR(pkt)  \
    ((pkt)->flags &= (~BCM_PKT_F_HGHDR)) 

#define BCM_PKT_HGHDR_REQUIRE(pkt)  \
    ((pkt)->flags |= BCM_PKT_F_HGHDR) 

#define BCM_PKT_SLTAG_REQUIRE(pkt)  \
    ((pkt)->flags |= BCM_PKT_F_SLTAG) 

/* How many bytes in the data blocks. */
#define BCM_PKT_BLK_BYTES_CALC(pkt, bytes)  \
    do { \
        int i; \
        (bytes) = 0; \
        for (i = 0; i < (pkt)->blk_count; i++) { \
            (bytes) += (pkt)->pkt_data[i].len; \
        } \
    } while (0) 

/* Packet length calculated based on flags. */
#define BCM_PKT_TX_LEN(pkt, bytes)  \
    do { \
        BCM_PKT_BLK_BYTES_CALC(pkt, bytes); \
        if (BCM_PKT_HAS_HGHDR(pkt)) (bytes) += 12; \
        if (BCM_PKT_HAS_SLTAG(pkt)) (bytes) += 4; \
        if ((pkt)->flags & BCM_PKT_F_NO_VTAG) (bytes) += 4; \
    } while (0) 

/* Packet length including SL, HiGig, VLAN tags. */
#define BCM_PKT_RX_TOT_LEN(pkt, bytes)  \
    (bytes) = (pkt)->tot_len 

/* 
 * BCM packet allocation function.
 * 
 * If unit is specified, the flags should be set up according to the unit
 * as best as possible.
 * 
 * If len > 0, then a packet buffer should be allocated and the packet
 * will be setup up for a single data block. If len <= 0, no packet
 * allocation will be made.
 */
typedef int (*bcm_pkt_alloc_f)(
    int unit, 
    int len, 
    bcm_pkt_t **pkt_buf);

/* BCM packet free function. */
typedef int (*bcm_pkt_free_f)(
    int unit, 
    bcm_pkt_t *pkt);

/* Map target ports according to VLAN and L2 tables. */
typedef int (*bcm_pkt_l2_map_f)(
    int unit, 
    bcm_pkt_t *pkt, 
    bcm_mac_t dest_mac, 
    int vid);

/* Initialize and set up a bcm_pkt_t structure. */
extern int bcm_pkt_clear(
    int unit, 
    bcm_pkt_t *pkt, 
    bcm_pkt_blk_t *blks, 
    int blk_count, 
    uint32 flags, 
    bcm_pkt_t **pkt_buf);

/* Initialize packet flags based on the type of device. */
extern int bcm_pkt_flags_init(
    int unit, 
    bcm_pkt_t *pkt, 
    uint32 init_flags);

/* Set up the length and flags for a bcm_pkt_t structure. */
extern int bcm_pkt_flags_len_setup(
    int unit, 
    bcm_pkt_t *pkt, 
    int alloc_bytes, 
    int payload_len, 
    uint32 flags);

/* Copy data into the data blocks of a packet structure. */
extern int bcm_pkt_memcpy(
    bcm_pkt_t *pkt, 
    int dest_byte, 
    uint8 *src, 
    int len);

/* Calculate a byte offset in the data buffer for a packet. */
extern int bcm_pkt_byte_index(
    bcm_pkt_t *pkt, 
    int n, 
    int *len, 
    int *blk_idx, 
    uint8 **location);

/* Allocate a packet structure and packet data. */
extern int bcm_pkt_alloc(
    int unit, 
    int size, 
    uint32 flags, 
    bcm_pkt_t **pkt_buf);

/* Deallocate a packet structure and packet data. */
extern int bcm_pkt_free(
    int unit, 
    bcm_pkt_t *pkt);

/* Allocate or deallocate an array of packets. */
extern int bcm_pkt_blk_alloc(
    int unit, 
    int count, 
    int size, 
    uint32 flags, 
    bcm_pkt_t ***packet_array);

/* Allocate or deallocate an array of packets. */
extern int bcm_pkt_blk_free(
    int unit, 
    bcm_pkt_t **pkt, 
    int count);

/* Allocate or deallocate a packet structure using =bcm_rx_alloc. */
extern int bcm_pkt_rx_alloc(
    int unit, 
    int len, 
    bcm_pkt_t **pkt_buf);

/* Allocate or deallocate a packet structure using =bcm_rx_alloc. */
extern int bcm_pkt_rx_free(
    int unit, 
    bcm_pkt_t *pkt);

/* Initialize a BCM packet structure. */
extern void bcm_pkt_t_init(
    bcm_pkt_t *pkt);

/* Initialize a BCM packet block structure. */
extern void bcm_pkt_blk_t_init(
    bcm_pkt_blk_t *pkt_blk);

#endif /* __BCM_PKT_H__ */
